﻿using System;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Ninject.Core;
using Nvigorate.Common.Reflection;
using Nvigorate.TestObjects;
using Nvigorate.Validation;
namespace Nvigorate.Test.Validation
{
   /// <summary>
    /// Summary description for ValidationTests
    /// </summary>
    [TestClass]
    public class ValidationTests
    {
        [TestMethod]
        public void TestSSNValidation_Pass()
        {
            //var rule = new ValidationRule<Employee>(e => e.SocialSecurity, "Valid Social Security Number");

            //rule.MustMatch("[0-9]{3}[- ]{1}[0-9]{2}[- ]{1}[0-9]{4}");
            //rule.Require(ssn => int.Parse(ssn.SubString(1, 3)) < 772);
            //rule.CannotBeginWith("666");
            //rule.CannotBeginWith("000");
            //rule.CannotEndWith("0000");
            //rule.CannotContian("00", 4, 2);
        }

        [TestMethod]
        public void TestSimpleRule()
        {
            //var rule = Validate
            //            .ForType<Employee>()
            //            .Create(e => e.SocialSecurity, Context.Universal, "Valid Social Security Number");

            //rule.MustMatch("[0-9]{3}[- ]{1}[0-9]{2}[- ]{1}[0-9]{4}");
            //rule.Require(ssn => int.Parse(ssn.SubString(1, 3)) < 772);
            //rule.CannotBeginWith("666");
            //rule.CannotBeginWith("000");
            //rule.CannotEndWith("0000");
            //rule.CannotContian("00", 4, 2);



            ValidationRule<Employee>.Assert(e => e.SocialSecurity);
                //MustBeginWith("")
                //CanBeginWith("","","")
                //
                //CannotBeginWith("")
                //CannotBeginWith("","","")
                //
                //MustEndWith("")
                //CanEndWith("","","")
                //
                //CannotEndWith("")
                //CannotEndWith("","","")
                //
                //MustMatch(regex)
                //MustMatch(regex, 1, 3)
                //
                //CannotMatch(regex)
                //CannotMatch(regex, 1, 3)
                //
                //MustContain(string, 1, 3)
                //CannotContain(string, 1, 3)
                //
                //Forbid(Predicate)
                //Require(Predicate)


            ValidationRule<Employee>.Assert(e => e.Employees);
                //NoMoreThan(x)
                //NoLessThan(x)
                //Exactly(x)


            ValidationRule<Employee>.Assert(e => e.Employees.Count);
                //GreaterThan(x)
                //GreaterOrEqualTo(x)
                //
                //LessThan(x)
                //LessOrEqualTo(x)
                //
                //EqualTo(x)
                //Between(x, y)
                //
                //Even()
                //Odd()
                //DvisibleBy(x)
                //
                //
                
                //Common Extensions
                //
                //When(Predicate<TTarget>)
                //Unless(Predicate<TTarget>)
                //
                //
                //
                //
                //
                //
                //
                //
                //
                //
        }
    }


}

namespace Nvigorate.Validation
{

    public enum Context
    {
        Domain,
        Persistence,
        UserInterface,
        Universal
    }

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class ContextAttribute : Attribute
    {
        public string Context { get; set; }

        public ContextAttribute(string context)
        {
            Context = context;
        }

        public ContextAttribute(Context context)
        {
            Context = context.ToString();
        }
    }

    public interface IValidationEngine
    {
        List<IViolation> Violations { get; set; }

        void CheckRules<TTarget>(Context context, TTarget target);
        void CheckRules<TTarget>(string context, TTarget target);
    }

    public abstract class ValidationEngineBase : IValidationEngine
    {
        protected List<IViolation> _violations = new List<IViolation>();

        public virtual List<IViolation> Violations
        {
            get { return _violations; }
            set { _violations = value; }
        }

        public virtual void CheckRules<TTarget>(Context context, TTarget target)
        {

        }

        public virtual void CheckRules<TTarget>(string context, TTarget target)
        {

        }
    }

    public class TypeRule<TTarget>
    {
        public IRule<TTarget, TValueType> Create<TValueType>(Expression<Func<TTarget, TValueType>> property, Context context, string ruleName)
        {
            return new object() as IRule<TTarget, TValueType>;
        }

        public IRule<TTarget, TValueType> Create<TValueType>(Expression<Func<TTarget, TValueType>> property, string context, string ruleName)
        {
            return new object() as IRule<TTarget, TValueType>;
        }
    }

    public interface IRule<TTarget, TValueType>
    {
        Expression<Func<TTarget, TValueType>> Property { get; set; }
        string Context { get; set; }
        string Name { get; set; }
    }



    public interface IValidationRule<TTarget>
    {
        PropertyInfo TargetProperty { get; set; }
        List<IViolation> Violations { get; }

        IValidationRule<TTarget> Evaluate(TTarget target);
    }

    public interface IViolation
    {

    }

    public interface ITranslator
    {
        ITranslator RegisterTypeName<TTarget>(string friendlyName);

        ITranslator RegisterPropertyName<TTarget, TProperty>(Expression<Func<TTarget, TProperty>> propertyExpression,
                                                             string friendlyName);

        string Translate(IViolation violation);
    }

    public interface IAssertion<TTarget>
    {
        
    }

    public abstract class TranslatorBase : ITranslator
    {
        protected Dictionary<PropertyInfo, string> _propertyLookup = new Dictionary<PropertyInfo, string>();
        protected Dictionary<Type, string> _typeLookup = new Dictionary<Type, string>();

        public ITranslator RegisterTypeName<TTarget>(string friendlyName)
        {
            _typeLookup[typeof(TTarget)] = friendlyName;
            return this;
        }

        public ITranslator RegisterPropertyName<TTarget, TProperty>(Expression<Func<TTarget, TProperty>> propertyExpression, string friendlyName)
        {
            var memberInfo = (propertyExpression.Body as MemberExpression).Member;
            _propertyLookup[Reflector.GetPropertyInfo(typeof(TTarget), memberInfo.Name, true)] = friendlyName;
            return this;
        }

        public string Translate(IViolation violation)
        {
            return "";
        }
    }

    public abstract class RuleBase<TTarget, TRule> : IValidationRule<TTarget>
        where TRule : class, IValidationRule<TTarget>, new()
    {
        protected List<IViolation> _violations = new List<IViolation>();
        protected List<IAssertion<TTarget>> _assertions = new List<IAssertion<TTarget>>();

        public virtual PropertyInfo TargetProperty { get; set; }

        public virtual List<IViolation> Violations
        {
            get { return _violations; }
        }

        public IValidationRule<TTarget> Evaluate(TTarget target)
        {
            throw new NotImplementedException();
        }

        public virtual List<IAssertion<TTarget>> Assertions
        {
            get { return _assertions; }
        }

        public virtual IValidationRule<TTarget> Evaluate(TTarget target, string context)
        {

            return this;
        }

        public static TRule Assert<TProperty>(Expression<Func<TTarget, TProperty>> propertyExpression)
        {
            var memberInfo = (propertyExpression.Body as MemberExpression).Member;
            return new TRule() { TargetProperty = Reflector.GetPropertyInfo(typeof(TTarget), memberInfo.Name, true) };
        }
    }

    public class ValidationRule<TTarget> : RuleBase<TTarget, ValidationRule<TTarget>>, IValidationRule<TTarget>
    {
        
        
    }
}
